Alejandro Betancur Quiroz
Se cuenta con información del número de registros diarios de vehículos en el Registro Único Nacional de Tránsito (RUNT). Se desea construir un modelo de aprendizaje que pueda realizar predicciones para esta variable llamada a partir de ahora value. El modelo no podra incurrir en overffiting por lo que la diferencia entre el coeficiente de derminación del periodo de entrenamiento y el periodo de prueba no podrá ser mayor al 10%.
Respecto a las variables explicativas, estas deberán ser independientes a value por lo que no se podrán construir modelos autoregresivos o basados en rezagos de esta variable. Las variables escogidas se discuten en una sección posterior.
import pathlib
import numpy as np
import pandas as pd
import datetime as dt
from sklearn import preprocessing
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import plotly.graph_objects as go
from joblib import dump, load
# import plotly.io as pio
# pio.renderers.default = "notebook"
def make_lag_correlations_two_varaibles(df_no_lag, df_lag, n_shifts, date_start, date_end, method='spearman'):
corrs = pd.concat(
[df_no_lag] + [df_lag.shift(shift) for shift in range(0, n_shifts)], axis=1
).loc[date_start:date_end].corr(method=method)
corrs = corrs.loc[:, [df_no_lag.columns[0]]].iloc[1:].reset_index(drop=True)
return corrs
data = pd.read_csv('./data/processed/dataset.csv', index_col=0)
data.index = pd.to_datetime(data.index)
data = data.drop(columns=['value_no_cl',])
pd.set_option('display.float_format', lambda x: '%.5f' % x)
X = data.drop(columns='value')
y = data.loc[:, ['value']]
X_train = X.loc['2012-01-01':'2016-12-31']
y_train = y.loc['2012-01-01':'2016-12-31']
X_val = X.loc['2017-01-01':'2017-12-31']
y_val = y.loc['2017-01-01':'2017-12-31']
X_test = X.loc['2018-01-01':'2018-06-30']
Corresponde a la variable que se desea predeccir (value), en este caso la cantidad de resitros en el RUNT.
Como puede notarse en la siguiente gráfica, los datos tienen un ciclo semanal y un ciclo anual. Debido a esto se presentan el mayor número de registro entre los días martes y viernes. Además, se presentan también un mayor número de registros a final de año.
# remove_cell
df_plot = pd.concat([y_train, y_val], axis=0)
df_plot.loc[y_train.index, 'periodo'] = 'entrenamiento'
df_plot.loc[y_val.index, 'periodo'] = 'validacion'
fig = px.line(
df_plot, x=df_plot.index, y=df_plot.columns, color='periodo', line_shape="spline", render_mode="svg"
)
fig.update_xaxes(rangeslider_visible=True)
fig.update_layout(
title='Número de registros RUNT',
xaxis_title="Fecha",
yaxis_title="Número de registros por día",
legend_title="Periodo",
# font=dict(
# family="Courier New, monospace",
# size=18,
# color="RebeccaPurple"
# )
)
fig.show()
Cabe destacar que los registros presentan una diferencia en la media, tal como se nota en la gráfica anterior y también al realizar un agrupamiento por semana (siguiente figura).
df_plot = pd.concat([y_train, y_val], axis=0)
df_plot.loc[y_train.index, 'periodo'] = 'entrenamiento'
df_plot.loc[y_val.index, 'periodo'] = 'validacion'
# df_plot = df_plot.rolling(window=7).mean()
df_plot = df_plot.resample('W-MON').sum()
fig = px.line(
df_plot, x=df_plot.index, y=df_plot.columns, render_mode="svg"
)
fig.update_xaxes(rangeslider_visible=True)
fig.update_layout(
title='Número de registros RUNT',
xaxis_title="Fecha",
yaxis_title="Número de registros por semana",
legend_title="Periodo",
# font=dict(
# family="Courier New, monospace",
# size=18,
# color="RebeccaPurple"
# )
)
fig.show()
Como se resaltó anteriormente los datos presentan diferentes periodicidades, por lo que esta característica se tomará en cuento realizando una descomposición en términos de senos y cosenos el día de la semana, el número de la semana y el mes.
En las siguientes gráficas se representan coseno Vs. seno de cada una de estas variables, donde el tamaño representa la cantidad media
# hide
df_plot_train = pd.concat([
X_train.groupby(by=[X_train.index.weekday]).mean(),
y_train.groupby(by=[y_train.index.weekday]).mean()
], axis=1)
df_plot_train.loc[:, 'periodo'] = 'entrenamiento'
df_plot_val = pd.concat([
X_val.groupby(by=[X_val.index.weekday]).mean(),
y_val.groupby(by=[y_val.index.weekday]).mean()
], axis=1)
df_plot_val.loc[:, 'periodo'] = 'validacion'
df_plot = pd.concat([df_plot_train, df_plot_val], axis=0)
fig = px.scatter(df_plot, x='cos_weekday', y='sin_weekday', color="value",
size='value', facet_col='periodo'
)
fig.update_yaxes(
scaleanchor = "x",
scaleratio = 1,
)
fig.show()
df_plot_train = pd.concat([
X_train.groupby(by=[X_train.index.isocalendar().week]).mean(),
y_train.groupby(by=[y_train.index.isocalendar().week]).mean()
], axis=1)
df_plot_train.loc[:, 'periodo'] = 'entrenamiento'
df_plot_val = pd.concat([
X_val.groupby(by=[X_val.index.isocalendar().week]).mean(),
y_val.groupby(by=[y_val.index.isocalendar().week]).mean()
], axis=1)
df_plot_val.loc[:, 'periodo'] = 'validacion'
df_plot = pd.concat([df_plot_train, df_plot_val], axis=0)
fig = px.scatter(df_plot, x='cos_n_week', y='sin_n_week', color="value",
size='value', facet_col='periodo'
)
fig.update_yaxes(
scaleanchor = "x",
scaleratio = 1,
)
fig.show()
df_plot_train = pd.concat([
X_train.groupby(by=[X_train.index.month]).mean(),
y_train.groupby(by=[y_train.index.month]).mean()
], axis=1)
df_plot_train.loc[:, 'periodo'] = 'entrenamiento'
df_plot_val = pd.concat([
X_val.groupby(by=[X_val.index.month]).mean(),
y_val.groupby(by=[y_val.index.month]).mean()
], axis=1)
df_plot_val.loc[:, 'periodo'] = 'validacion'
df_plot = pd.concat([df_plot_train, df_plot_val], axis=0)
fig = px.scatter(df_plot, x='cos_month', y='sin_month', color="value",
size='value', facet_col='periodo'
)
fig.update_yaxes(
scaleanchor = "x",
scaleratio = 1,
)
fig.show()
Empleando el paquete holidays_co de Python se construyó la variable holiday la cual toma el valor de 1 si la fecha correspondiente es un día festivo y 0 en caso contrario. Así mismo, al partir de esta variable se construyeron también las variables day_before_holiday y week_with_holiday. La primera toma el valor de 1 si el día anterior fue un día festivo (0 en caso contrario) y la segunda toma el valor de 1 si en la semana a la cual pertenece el día hubo un día festivo (0 en caso contrario).
data.iloc[0:14].loc[:, ['holiday', 'day_before_holiday', 'week_with_holiday']]
| holiday | day_before_holiday | week_with_holiday | |
|---|---|---|---|
| 2012-01-01 | 1.00000 | 0.00000 | 1.00000 |
| 2012-01-02 | 0.00000 | 1.00000 | 0.00000 |
| 2012-01-03 | 0.00000 | 0.00000 | 0.00000 |
| 2012-01-04 | 0.00000 | 0.00000 | 0.00000 |
| 2012-01-05 | 0.00000 | 0.00000 | 0.00000 |
| 2012-01-06 | 0.00000 | 0.00000 | 0.00000 |
| 2012-01-07 | 0.00000 | 0.00000 | 0.00000 |
| 2012-01-08 | 0.00000 | 0.00000 | 0.00000 |
| 2012-01-09 | 1.00000 | 0.00000 | 1.00000 |
| 2012-01-10 | 0.00000 | 1.00000 | 1.00000 |
| 2012-01-11 | 0.00000 | 0.00000 | 1.00000 |
| 2012-01-12 | 0.00000 | 0.00000 | 1.00000 |
| 2012-01-13 | 0.00000 | 0.00000 | 1.00000 |
| 2012-01-14 | 0.00000 | 0.00000 | 1.00000 |
La información del histórico de la Tasa Representativa del Mercado (TRM) del Dólar en Colombia se obtuvo de la página de Datos Abiertos del Gobierno de Colombia (link de descarga).
A partir de un correlograma entre la variable trm y valuese determinaron rezagos de la TRM con importancia para ser incluidos en el modelo. A continuación se presenta dicho correlograma y la serie historica de la TRM.
data_trm_raw = pd.read_csv('./data/raw/Tasa_de_Cambio_Representativa_del__Mercado_-Historico.csv')
data_trm_raw.loc[:, 'VIGENCIADESDE'] = pd.to_datetime(data_trm_raw.loc[:, 'VIGENCIADESDE'], format='%d/%m/%Y')
data_trm_raw.loc[:, 'VIGENCIAHASTA'] = pd.to_datetime(data_trm_raw.loc[:, 'VIGENCIAHASTA'], format='%d/%m/%Y')
data_trm = pd.DataFrame(columns=['trm'])
for aux, ii in enumerate(data_trm_raw.index):
date_start = data_trm_raw.loc[ii, 'VIGENCIADESDE']
date_end = data_trm_raw.loc[ii, 'VIGENCIAHASTA']
value = data_trm_raw.loc[ii, 'VALOR']
date_range = pd.date_range(date_start, date_end, freq='D')
df_tmp = pd.DataFrame(data=np.ones(len(date_range))*value, index=date_range, columns=['trm'])
data_trm = pd.concat([data_trm, df_tmp], axis=0)
data_trm.index = pd.to_datetime(data_trm.index)
data_trm = data_trm.sort_index()
data_trm = data_trm.astype(float)
data_trm = data_trm.asfreq('D')
data_trm = data_trm.rolling(window=7).mean()
df_plot = df_plot_train = make_lag_correlations_two_varaibles(
df_no_lag=data.loc[:, ['value']], df_lag=data_trm, n_shifts=720,
date_start='2012-01-01', date_end='2017-12-31', method='spearman'
)
df_lags = df_plot.loc[[45, 60, 404, 592]]
df_lags.columns = ['Correlacion']
df_lags.loc[:, 'color'] = ['Rezago 45', 'Rezago 60', 'Rezago 04', 'Rezago 592']
df_lags.loc[:, 'size'] = [10, 10, 10, 10]
fig1 = px.line(df_plot, x=df_plot.index, y='value', height=400)
fig2 = px.scatter(df_lags, x=df_lags.index, y="Correlacion", color='color', size='size')
fig = go.Figure(data=fig1.data + fig2.data)
fig.show()
df_plot
| trm_shift_45 | trm_shift_60 | trm_shift_404 | trm_shift_592 | periodo | |
|---|---|---|---|---|---|
| 2012-01-01 | 1913.69429 | 1870.42714 | 1875.82143 | 1967.83429 | entrenamiento |
| 2012-01-02 | 1913.29143 | 1872.07857 | 1877.51571 | 1972.22429 | entrenamiento |
| 2012-01-03 | 1913.83429 | 1878.15571 | 1879.42000 | 1980.51857 | entrenamiento |
| 2012-01-04 | 1914.37714 | 1885.67857 | 1882.74714 | 1984.85000 | entrenamiento |
| 2012-01-05 | 1914.92000 | 1893.20143 | 1887.21857 | 1989.18143 | entrenamiento |
| ... | ... | ... | ... | ... | ... |
| 2018-06-26 | 2839.42143 | 2784.52429 | 2905.78286 | 3054.08857 | NaN |
| 2018-06-27 | 2836.65571 | 2791.42714 | 2905.53143 | 3058.33429 | NaN |
| 2018-06-28 | 2833.89000 | 2798.33000 | 2901.35429 | 3062.58000 | NaN |
| 2018-06-29 | 2834.86857 | 2805.23286 | 2897.17714 | 3066.82571 | NaN |
| 2018-06-30 | 2838.27857 | 2806.72857 | 2893.00000 | 3071.07143 | NaN |
2373 rows × 5 columns
df_plot = data.filter(regex=("trm.*")).dropna()
fig = px.line(
df_plot, x=df_plot.index, y=df_plot.columns, render_mode="svg"
)
fig.update_xaxes(rangeslider_visible=True)
fig.update_layout(
title='Número de registros RUNT',
xaxis_title="Fecha",
yaxis_title="TRM [COP]"
# font=dict(
# family="Courier New, monospace",
# size=18,
# color="RebeccaPurple"
# )
)
fig.show()
Empleando el paquete pytrends se obtienen los registros de busqueda en Colombia de las palabras carro, moto y RUNT en Google. Y al igual que para la TRM se utiliza una estrategia de correlaciones rezagadas con value para seleccionar rezagos con importancia.
Las series de estas varaibles se presentan a continuación:
df_plot = data.filter(regex=("gt.*")).dropna()
fig = px.line(
df_plot, x=df_plot.index, y=df_plot.columns, render_mode="svg"
)
fig.update_xaxes(rangeslider_visible=True)
fig.update_layout(
title='Variables derivadas de Goole Trends',
xaxis_title="Fecha",
yaxis_title="Número de busquedas en Google"
# font=dict(
# family="Courier New, monospace",
# size=18,
# color="RebeccaPurple"
# )
)
fig.show()
El conjunto de datos final derivado de las variables previamente mencionadas tiene esta forma:
pd.concat([y, X], axis=1).head()
| value | cos_month | sin_month | cos_n_week | sin_n_week | cos_weekday | sin_weekday | holiday | day_before_holiday | week_with_holiday | trm_shift_45 | trm_shift_60 | trm_shift_404 | trm_shift_592 | gt_carro | gt_moto | gt_RUNT | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2012-01-01 | 0.00000 | 0.86603 | 0.50000 | 1.00000 | 0.00000 | 0.62349 | -0.78183 | 1.00000 | 0.00000 | 1.00000 | 1913.69429 | 1870.42714 | 1875.82143 | 1967.83429 | 468.00000 | 339.00000 | 148.00000 |
| 2012-01-02 | 188.00000 | 0.86603 | 0.50000 | 0.99271 | 0.12054 | 1.00000 | 0.00000 | 0.00000 | 1.00000 | 0.00000 | 1913.29143 | 1872.07857 | 1877.51571 | 1972.22429 | 557.00000 | 297.00000 | 125.00000 |
| 2012-01-03 | 482.00000 | 0.86603 | 0.50000 | 0.99271 | 0.12054 | 0.62349 | 0.78183 | 0.00000 | 0.00000 | 0.00000 | 1913.83429 | 1878.15571 | 1879.42000 | 1980.51857 | 344.00000 | 266.00000 | 371.00000 |
| 2012-01-04 | 927.00000 | 0.86603 | 0.50000 | 0.99271 | 0.12054 | -0.22252 | 0.97493 | 0.00000 | 0.00000 | 0.00000 | 1914.37714 | 1885.67857 | 1882.74714 | 1984.85000 | 516.00000 | 327.00000 | 296.00000 |
| 2012-01-05 | 1159.00000 | 0.86603 | 0.50000 | 0.99271 | 0.12054 | -0.90097 | 0.43388 | 0.00000 | 0.00000 | 0.00000 | 1914.92000 | 1893.20143 | 1887.21857 | 1989.18143 | 323.00000 | 367.00000 | 408.00000 |
data_plot = pd.concat([y, X], axis=1).loc['2012-01-01':'2017-12-31'].corr(method='spearman')
fig = px.imshow(data_plot, text_auto=True, aspect="auto", color_continuous_scale='RdBu_r', zmin=-1, zmax=1)
fig.show()
#
# fig = plt.figure(figsize=(12, 12))
# ax = sns.heatmap(data_corr, annot=True, linewidths=.5, vmin=-1, vmax=1, cmap='bwr', fmt='.2f')
# plt.show()
# plt.close('all')
Dada la correlación entre las diferentes variables (gráfica anterior) se toma la decisión de procesar las variables de entrada empleando PCA. Sin embargo, antes de esto las variables se escalan para evitar los efectos de la diferencia de magnitud entre las diferentes variables.
A continuación, se muestran las componentes pricipales y la varianza explicada por cada componente principal.
pipeline = load(str(pathlib.Path('./outputs/pipeline.joblib')))
# data_plot = pd.DataFrame(pipeline.transform(X_train), index=X_train.index)
data_plot = pd.DataFrame(pipeline['pca'].components_)
data_plot.columns = [f'componente {ii}' for ii in data_plot.columns]
fig = px.line(data_plot, x=data_plot.index, y=data_plot.columns, title='Componentes principales')
# fig.update_xaxes(rangeslider_visible=True)
fig.show()
data_plot = pd.DataFrame(np.cumsum(pipeline['pca'].explained_variance_ratio_))
fig1 = px.line(data_plot, x=data_plot.index, y=data_plot.columns, title='Porcentaje de varianza explicado')
data_plot = pd.DataFrame(pipeline['pca'].explained_variance_ratio_)
fig2 = px.bar(data_plot, x=data_plot.index, y=data_plot.columns)
fig = go.Figure(data=fig1.data + fig2.data)
fig.show()
Los modelos se entrenaron en un esquema de validación cruzada temporal (TimeSeriesSplit de Sklearn) en el periodo de entrenamiento. La siguiente figura esquematiza dicho esquema y fue tomada de la documentación de la función en Sklearn.
.png)
Además, se seleccionaron los mejores hiperparámetros mediante GridSearchCV de Sklearn empleando el MSE como métrica de evaluación. Además, cabe destacar que también se realizó tuning del número de componentes principales empleadas para el pronóstico.
A continuación, se presentan los diferentes hiperparámetros probados junto con el mejor conjunto de entrenamiento para cada uno de los modelos evaluados. Sumado a esto, se realizó un análisis de importancia de variables de los modelos entrenados empleando permutation_importance` de Sklearn y usando RMSE como métrica de evaluación, estos resultados también se presentan para cada modelo.
Los hiperpárametros empleados fueron: {'estimator__alpha': np.logspace(-4, 6, 100)}
Los mejores hiperpárametros encontrados son: {'estimatoralpha': 1.747528400007683, 'pcan_components': 13}
El gráfico cuantil-cuantil de este modelo para ambos peridos es:

Así mismo, los resultados de análisis de importancia empleando permutación es:
pd.read_csv('./outputs/importancia_variables_Ridge.csv', index_col=0)
| importances_mean | importances_std | feature | |
|---|---|---|---|
| 5 | 0.05358 | 0.00666 | sin_weekday |
| 4 | 0.02361 | 0.00327 | cos_weekday |
| 6 | 0.01408 | 0.00301 | holiday |
| 7 | 0.00091 | 0.00095 | day_before_holiday |
| 8 | 0.00053 | 0.00017 | week_with_holiday |
| 11 | -0.00001 | 0.00006 | trm_shift_404 |
| 0 | -0.00007 | 0.00029 | cos_month |
| 3 | -0.00007 | 0.00008 | sin_n_week |
| 12 | -0.00009 | 0.00005 | trm_shift_592 |
| 13 | -0.00009 | 0.00003 | gt_carro |
| 1 | -0.00012 | 0.00015 | sin_month |
| 2 | -0.00013 | 0.00014 | cos_n_week |
| 9 | -0.00020 | 0.00014 | trm_shift_45 |
| 10 | -0.00024 | 0.00019 | trm_shift_60 |
| 15 | -0.00051 | 0.00020 | gt_RUNT |
| 14 | -0.00063 | 0.00032 | gt_moto |
Los hiperpárametros empleados fueron: {'estimator__alpha': np.logspace(-4, 6, 100)}
Los mejores hiperpárametros encontrados son: {'estimatoralpha': 1.747528400007683, 'pcan_components': 13}
El gráfico cuantil-cuantil de este modelo para ambos peridos es:

Así mismo, los resultados de análisis de importancia empleando permutación es:
pd.read_csv('./outputs/importancia_variables_Ridge.csv', index_col=0)
| importances_mean | importances_std | feature | |
|---|---|---|---|
| 5 | 0.05358 | 0.00666 | sin_weekday |
| 4 | 0.02361 | 0.00327 | cos_weekday |
| 6 | 0.01408 | 0.00301 | holiday |
| 7 | 0.00091 | 0.00095 | day_before_holiday |
| 8 | 0.00053 | 0.00017 | week_with_holiday |
| 11 | -0.00001 | 0.00006 | trm_shift_404 |
| 0 | -0.00007 | 0.00029 | cos_month |
| 3 | -0.00007 | 0.00008 | sin_n_week |
| 12 | -0.00009 | 0.00005 | trm_shift_592 |
| 13 | -0.00009 | 0.00003 | gt_carro |
| 1 | -0.00012 | 0.00015 | sin_month |
| 2 | -0.00013 | 0.00014 | cos_n_week |
| 9 | -0.00020 | 0.00014 | trm_shift_45 |
| 10 | -0.00024 | 0.00019 | trm_shift_60 |
| 15 | -0.00051 | 0.00020 | gt_RUNT |
| 14 | -0.00063 | 0.00032 | gt_moto |
Los hiperpárametros empleados fueron: {'estimator__alpha': np.logspace(-4, 6, 100)}
Los mejores hiperpárametros encontrados son: {'estimatoralpha': 0.001788649529057435, 'pcan_components': 13}
El gráfico cuantil-cuantil de este modelo para ambos peridos es:

Así mismo, los resultados de análisis de importancia empleando permutación es:
pd.read_csv('./outputs/importancia_variables_Lasso.csv', index_col=0)
| importances_mean | importances_std | feature | |
|---|---|---|---|
| 5 | 0.05144 | 0.00640 | sin_weekday |
| 4 | 0.02180 | 0.00302 | cos_weekday |
| 6 | 0.01027 | 0.00220 | holiday |
| 8 | 0.00093 | 0.00030 | week_with_holiday |
| 15 | 0.00075 | 0.00029 | gt_RUNT |
| 7 | 0.00062 | 0.00065 | day_before_holiday |
| 13 | 0.00010 | 0.00003 | gt_carro |
| 14 | 0.00007 | 0.00004 | gt_moto |
| 12 | 0.00002 | 0.00001 | trm_shift_592 |
| 11 | -0.00000 | 0.00000 | trm_shift_404 |
| 0 | -0.00006 | 0.00023 | cos_month |
| 3 | -0.00006 | 0.00007 | sin_n_week |
| 1 | -0.00006 | 0.00008 | sin_month |
| 2 | -0.00010 | 0.00011 | cos_n_week |
| 9 | -0.00012 | 0.00009 | trm_shift_45 |
| 10 | -0.00017 | 0.00014 | trm_shift_60 |
Los hiperpárametros empleados fueron: { 'estimatorn_neighbors': range(3, 30), 'estimatorweights': ['uniform','distance'], 'estimator__p': [1, 2, 3], }
Los mejores hiperpárametros encontrados son:
{'estimatorn_neighbors': 7, 'estimatorp': 1, 'estimatorweights': 'distance', 'pcan_components': 10}
El gráfico cuantil-cuantil de este modelo para ambos peridos es:

Así mismo, los resultados de análisis de importancia empleando permutación es:
pd.read_csv('./outputs/importancia_variables_KNeighborsRegressor.csv', index_col=0)
| importances_mean | importances_std | feature | |
|---|---|---|---|
| 5 | 0.06376 | 0.00766 | sin_weekday |
| 4 | 0.04997 | 0.00533 | cos_weekday |
| 14 | 0.01795 | 0.00158 | gt_moto |
| 15 | 0.01358 | 0.00264 | gt_RUNT |
| 13 | 0.01344 | 0.00299 | gt_carro |
| 3 | 0.01122 | 0.00274 | sin_n_week |
| 1 | 0.01084 | 0.00260 | sin_month |
| 0 | 0.00814 | 0.00300 | cos_month |
| 10 | 0.00793 | 0.00202 | trm_shift_60 |
| 2 | 0.00769 | 0.00229 | cos_n_week |
| 11 | 0.00680 | 0.00090 | trm_shift_404 |
| 8 | 0.00675 | 0.00381 | week_with_holiday |
| 6 | 0.00649 | 0.00491 | holiday |
| 9 | 0.00627 | 0.00177 | trm_shift_45 |
| 12 | 0.00557 | 0.00160 | trm_shift_592 |
| 7 | 0.00224 | 0.00128 | day_before_holiday |
Los hiperpárametros empleados fueron: { 'estimatormax_features' : [1, 'sqrt', 'log2'], 'estimatorn_estimators': [400], 'estimator__max_depth': [3, 4, 5], }
Los mejores hiperpárametros encontrados son: {'estimatormax_depth': 5, 'estimatormax_features': 'sqrt', 'estimatorn_estimators': 400, 'pcan_components': 9}
El gráfico cuantil-cuantil de este modelo para ambos peridos es:

Así mismo, los resultados de análisis de importancia empleando permutación es:
pd.read_csv('./outputs/importancia_variables_RandomForestRegressor.csv', index_col=0)
| importances_mean | importances_std | feature | |
|---|---|---|---|
| 5 | 0.07425 | 0.00663 | sin_weekday |
| 4 | 0.02416 | 0.00220 | cos_weekday |
| 6 | 0.01979 | 0.00393 | holiday |
| 7 | 0.00550 | 0.00219 | day_before_holiday |
| 8 | 0.00489 | 0.00090 | week_with_holiday |
| 3 | 0.00075 | 0.00024 | sin_n_week |
| 13 | 0.00062 | 0.00062 | gt_carro |
| 1 | 0.00050 | 0.00026 | sin_month |
| 14 | 0.00047 | 0.00037 | gt_moto |
| 9 | 0.00045 | 0.00016 | trm_shift_45 |
| 10 | 0.00041 | 0.00020 | trm_shift_60 |
| 15 | 0.00030 | 0.00074 | gt_RUNT |
| 11 | 0.00024 | 0.00010 | trm_shift_404 |
| 12 | -0.00006 | 0.00006 | trm_shift_592 |
| 2 | -0.00062 | 0.00041 | cos_n_week |
| 0 | -0.00082 | 0.00033 | cos_month |
Los hiperpárametros empleados fueron:
{ 'estimatormax_features' : [1, 'sqrt', 'log2'], 'estimatormax_depth' : [1, 3, 5], 'estimatorsubsample' : [0.5, 1], 'estimatorlearning_rate' : [0.001, 0.01, 0.1], }
Los mejores hiperpárametros encontrados son:
{'estimatorlearning_rate': 0.1, 'estimatormax_depth': 5, 'estimatormax_features': 'sqrt', 'estimatorsubsample': 1, 'pca__n_components': 9}
El gráfico cuantil-cuantil de este modelo para ambos peridos es:

Así mismo, los resultados de análisis de importancia empleando permutación es:
pd.read_csv('./outputs/importancia_variables_GradientBoostingRegressor.csv', index_col=0)
| importances_mean | importances_std | feature | |
|---|---|---|---|
| 5 | 0.08014 | 0.00770 | sin_weekday |
| 4 | 0.04253 | 0.00426 | cos_weekday |
| 6 | 0.01936 | 0.00389 | holiday |
| 8 | 0.00537 | 0.00220 | week_with_holiday |
| 14 | 0.00422 | 0.00141 | gt_moto |
| 15 | 0.00417 | 0.00163 | gt_RUNT |
| 13 | 0.00381 | 0.00141 | gt_carro |
| 7 | 0.00348 | 0.00173 | day_before_holiday |
| 3 | 0.00263 | 0.00212 | sin_n_week |
| 1 | 0.00143 | 0.00228 | sin_month |
| 11 | 0.00099 | 0.00082 | trm_shift_404 |
| 10 | 0.00057 | 0.00122 | trm_shift_60 |
| 9 | 0.00054 | 0.00100 | trm_shift_45 |
| 12 | 0.00048 | 0.00058 | trm_shift_592 |
| 2 | -0.00881 | 0.00318 | cos_n_week |
| 0 | -0.00935 | 0.00262 | cos_month |
Los hiperpárametros empleados fueron:
{ 'estimatorC': [10, 50, 75], 'estimatorgamma': [0.1, 0.01, 0.001, 0.0001], 'estimator__kernel': ['rbf', 'poly', 'sigmoid', 'linear'] }
Los mejores hiperpárametros encontrados son:
{'estimatorC': 75, 'estimatorgamma': 0.01, 'estimatorkernel': 'rbf', 'pcan_components': 12}
El gráfico cuantil-cuantil de este modelo para ambos peridos es:

Así mismo, los resultados de análisis de importancia empleando permutación es:
pd.read_csv('./outputs/importancia_variables_SVR.csv', index_col=0)
| importances_mean | importances_std | feature | |
|---|---|---|---|
| 5 | 0.05929 | 0.00642 | sin_weekday |
| 4 | 0.03413 | 0.00382 | cos_weekday |
| 6 | 0.01922 | 0.00435 | holiday |
| 15 | 0.00202 | 0.00044 | gt_RUNT |
| 11 | 0.00023 | 0.00004 | trm_shift_404 |
| 12 | 0.00013 | 0.00001 | trm_shift_592 |
| 13 | -0.00002 | 0.00021 | gt_carro |
| 0 | -0.00008 | 0.00018 | cos_month |
| 7 | -0.00016 | 0.00114 | day_before_holiday |
| 14 | -0.00032 | 0.00028 | gt_moto |
| 2 | -0.00034 | 0.00031 | cos_n_week |
| 3 | -0.00088 | 0.00026 | sin_n_week |
| 9 | -0.00092 | 0.00020 | trm_shift_45 |
| 10 | -0.00131 | 0.00030 | trm_shift_60 |
| 8 | -0.00138 | 0.00081 | week_with_holiday |
| 1 | -0.00142 | 0.00032 | sin_month |
df_y_train_predict = pd.read_csv('./outputs/results_train.csv', index_col=0)
df_y_val_predict = pd.read_csv('./outputs/results_val.csv', index_col=0)
df_y_test_predict = pd.read_csv('./outputs/results_test.csv', index_col=0)
data_plot = df_y_train_predict
fig = px.line(data_plot, x=data_plot.index, y=data_plot.columns, title='Predicciones periodo de entrenamiento')
fig.update_xaxes(rangeslider_visible=True)
fig.show()
data_plot = df_y_val_predict
fig = px.line(data_plot, x=data_plot.index, y=data_plot.columns, title='Predicciones periodo de validación')
fig.update_xaxes(rangeslider_visible=True)
fig.show()
data_plot = df_y_test_predict
fig = px.line(data_plot, x=data_plot.index, y=data_plot.columns, title='Predicciones periodo de prueba')
fig.update_xaxes(rangeslider_visible=True)
fig.show()
Finalmente, se presentan diferentes métricas para los diferentes modelos evaluados.